#ifndef _XDGSOCKETIO_HPP_
#define _XDGSOCKETIO_HPP_

#include <iostream>
#include <string>
#include <vector>

// ======================= Linux/POSIX 平台所需的头文件 =======================
#include <sys/types.h>      // 提供基本系统数据类型, 如 ssize_t
#include <sys/socket.h>     // 提供核心 socket 函数和数据结构, 如 socket, bind, sockaddr
#include <netinet/in.h>     // 提供 sockaddr_in 和 sockaddr_in6 结构
#include <netinet/tcp.h>    // 适用于 TCP_NODELAY 等 TCP 选项
#include <arpa/inet.h>      // 适用于 inet_pton 和 inet_ntop
#include <unistd.h>         // 适用于 close(), fcntl() 等 POSIX 系统调用
#include <netdb.h>          // 适用于 getaddrinfo, getnameinfo, 等域名解析函数
#include <fcntl.h>          // 适用于 fcntl() 函数, 用于修改文件描述符属性
#include <stdexcept>        // 适用于在初始化失败时抛出异常
#include <cstring>          // 适用于 memset, 用于清零内存块
#include <cerrno>


namespace xdg
{

class SocketIO
{
/***************************************构造/析构函数****************************************/
private:
    /**
     * @brief 构造函数被设为私有。
     * @details 这是一个纯静态工具类, 不应该被实例化。
     */
    SocketIO() = default;

public:
    // 禁止拷贝、赋值、移动
    SocketIO(const SocketIO&) = delete;
    SocketIO& operator=(const SocketIO&) = delete;
    SocketIO(SocketIO&&) = delete;
    SocketIO& operator=(SocketIO&&) = delete;

/*************************************** Socket 底层封装接口 ****************************************/
public:
    //================================================================================================
    // 1. Socket生命周期与核心操作 (Lifecycle and Core Operations)
    //    - 所有函数都为静态, 需要显式传入文件描述符。
    //================================================================================================

    /**
     * @brief 根据指定的地址族，创建一个TCP套接字 (SOCK_STREAM)。
     * @param address_family AF_INET (IPv4) 或 AF_INET6 (IPv6)。
     * @return 成功则返回新创建的socket文件描述符, 失败返回-1。
     */
    static int createTcpSocket(int address_family);

    /**
     * @brief 根据指定的地址族，创建一个UDP套接字 (SOCK_DGRAM)。
     * @param address_family AF_INET (IPv4) 或 AF_INET6 (IPv6)。
     * @return 成功则返回新创建的socket文件描述符, 失败返回-1。
     */
    static int createUdpSocket(int address_family);

    /**
     * @brief 将套接字绑定到指定的IP地址和端口。
     * @param fd 要绑定的套接字文件描述符。
     * @param ip 要绑定的IP地址。
     * @param port 要绑定的端口号。
     * @return 成功返回0, 失败返回-1。
     */
    static int bindSocket(int fd, const std::string& ip, int port);

    /**
     * @brief 监听套接字，使其进入被动接收连接的状态。
     * @param fd 监听的套接字文件描述符。
     * @return 成功返回0, 失败返回-1。
     */
    static int listenSocket(int fd);

    /**
     * @brief 接受一个新的客户端连接。
     * @param fd 监听的套接字文件描述符。
     * @param client_addr [输出] 存储客户端地址信息的结构体的指针, 使用 sockaddr_storage 来兼容 IPv4 和 IPv6。
     * @return 成功则返回与客户端通信的新socket文件描述符, 失败返回-1。
     */
    static int acceptSocket(int fd, struct sockaddr_storage *client_addr = nullptr);

    /**
     * @brief 向指定IP和端口发起连接。
     * @param fd 用于连接的套接字文件描述符。
     * @param ip 目标服务器IP地址。
     * @param port 目标服务器端口号。
     * @return 成功返回0, 失败返回-1。
     */
    static int connectSocket(int fd, const std::string& ip, int port);
    
    /**
     * @brief 关闭Socket写端。
     * @param fd 用于通信的套接字文件描述符。
     */
    static int shutdownWrite(int fd);

    /**
     * @brief 关闭Socket读端。
     * @param fd 用于通信的套接字文件描述符。
     */
    static int shutdownRead(int fd);

    /**
     * @brief 关闭Socket读写端。
     * @param fd 用于通信的套接字文件描述符。
     */
    static int shutdownBoth(int fd);

    /**
     * @brief 关闭套接字Socket。
     * @param fd 欲关闭的套接字文件描述符。
     * @return 返回close()的实际返回值。
     */
    static int closeSocket(int fd);

    //================================================================================================
    // 2. 数据传输 (Data Transfer)
    //================================================================================================

    /**
    * @brief 发送指定长度的全部数据 (循环发送, 确保完整性)。
    * @param fd 用于通信的套接字文件描述符。
    * @param buf 包含待发送数据的缓冲区。
    * @param len 要发送数据的总长度。
    * @return 成功时返回实际发送的总字节数 (即len); 失败时返回-1。
    */
    static ssize_t sendSocket(int fd, const char *buf, size_t len);

    /**
     * @brief 接收数据 (TCP)。
     * @param fd 用于通信的套接字文件描述符。
     * @param buf 接收缓冲区。
     * @param len 接收缓冲区长度。
     * @return 返回recv()的实际返回值。
     */
    static ssize_t recvSocket(int fd, char *buf, size_t len);

    /**
     * @brief 接收固定长度的字节。
     * @details 该函数会持续调用 recv 直到接收到指定 len 长度的字节, 或者发生错误/连接关闭。
     * @param fd 文件描述符。
     * @param buf 接收缓冲区。
     * @param len 期望接收的固定字节数。
     * @return 成功返回接收的字节数(即len); 对端关闭连接返回0; 发生错误返回-1。
     */
    static ssize_t recvFixedLength(int fd, char *buf, size_t len);

    /**
     * @brief 接收数据直到遇到 "\\r\\n"。
     * @param fd 文件描述符。
     * @param out_line [输出] 用于存储结果的字符串。
     * @return bool 成功接收返回 true, 失败或连接关闭返回 false。
     */
    static bool recvLine(int fd, std::string& out_line);

    /**
     * @brief 按 "4字节头部(主机字节序长度) + 消息体" 的格式接收数据包。
     * @details 首先接收4个字节并直接解释为消息体的长度, 然后再接收该长度的消息体。
     * @param fd 文件描述符。
     * @param out_packet [输出] 用于存储结果的字节向量。
     * @param max_packet_size 允许接收的最大包体长度，防止恶意攻击。
     * @return ssize_t 成功返回数据包总长度, 对端关闭连接返回0, 错误返回-1, 包体超长返回-2。
     */
    static ssize_t recvPacket(int fd, std::vector<char>& out_packet, uint32_t max_packet_size);


    /**
     * @brief 从指定地址接收数据 (通常用于UDP)。
     * @param fd 用于通信的套接字文件描述符。
     * @param buf 接收数据的缓冲区。
     * @param len 缓冲区的最大长度。
     * @param flags 控制接收行为的标志 (通常为0)。
     * @param src_addr [输出] 指向sockaddr结构的指针，用于存储发送方的地址信息。
     * @param addrlen [输入/输出] 指向src_addr长度的指针；调用时应设为其初始大小，函数返回时会设为实际地址长度。
     * @return 成功时返回接收到的字节数，失败时返回-1。
     */
    static ssize_t recvfromSocket(int fd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
    
    /**
     * @brief 发送数据到指定地址 (通常用于UDP)。
     * @param fd 用于通信的套接字文件描述符。
     * @param buf 包含待发送数据的缓冲区。
     * @param len 要发送数据的长度。
     * @param flags 控制发送行为的标志 (通常为0)。
     * @param dest_addr 指向sockaddr结构的指针，包含了目标接收方的地址信息。
     * @param addrlen dest_addr结构的长度。
     * @return 成功时返回发送的字节数，失败时返回-1。
     */
    static ssize_t sendtoSocket(int fd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

    //================================================================================================
    // 3. Socket选项配置 (Socket Options Configuration)
    //================================================================================================

    /**
     * @brief 设置Socket为非阻塞模式。
     * @param fd 欲设置的套接字文件描述符。
     */
    static void setNonBlocking(int fd);

    /**
     * @brief 设置Socket为阻塞模式。
     * @param fd 欲设置的套接字文件描述符。
     */
    static void setBlocking(int fd);

    /**
     * @brief 设置地址重用选项 (SO_REUSEADDR)，允许一个地址被重复使用，通常用于多进程服务器。
     * @param fd 操作的套接字文件描述符。
     * @param on 是否开启。
     * @return 成功返回0, 失败返回-1。
     */
    static int setReuseAddr(int fd, bool on = true);

    /**
     * @brief 设置端口重用选项 (SO_REUSEPORT)，允许一个端口被重复使用，通常用于多进程服务器。
     * @param fd 操作的套接字文件描述符。
     * @param on 是否开启。
     * @return 成功返回0, 失败返回-1。
     */
    static int setReusePort(int fd, bool on = true);

    /**
     * @brief 设置TCP_NODELAY选项(禁用Nagle算法)。
     * @param fd 操作的套接字文件描述符。
     * @param on 是否开启。
     * @return 成功返回0, 失败返回-1。
     */
    static int setTcpNoDelay(int fd, bool on = true);

    /**
     * @brief 设置SO_KEEPALIVE选项（TCP保活机制）。
     * @param fd 操作的套接字文件描述符。
     * @param on 是否开启。
     * @return 成功返回0, 失败返回-1。
     */
    static int setKeepAlive(int fd, bool on = true);

    /**
     * @brief 设置接收缓冲区大小 (SO_RCVBUF)。
     * @param fd 操作的套接字文件描述符。
     * @param size 缓冲区大小(字节)。
     * @return 成功返回0, 失败返回-1。
     */
    static int setRecvBufferSize(int fd, int size);

    /**
     * @brief 设置发送缓冲区大小 (SO_SNDBUF)。
     * @param fd 操作的套接字文件描述符。
     * @param size 缓冲区大小(字节)。
     * @return 成功返回0, 失败返回-1。
     */
    static int setSendBufferSize(int fd, int size);

    /**
     * @brief 设置接收超时 (SO_RCVTIMEO)。
     * @param fd 操作的套接字文件描述符。
     * @param seconds 超时秒数。
     * @return 成功返回0, 失败返回-1。
     */
    static int setRecvTimeout(int fd, int seconds);

    /**
     * @brief 设置发送超时 (SO_SNDTIMEO)。
     * @param fd 操作的套接字文件描述符。
     * @param seconds 超时秒数。
     * @return 成功返回0, 失败返回-1。
     */
    static int setSendTimeout(int fd, int seconds);

    //================================================================================================
    // 4. 静态网络工具函数 (Static Network Utilities)
    //================================================================================================
    
    /**
     * @brief 将字符串形式的IP地址转换为网络二进制形式。
     * @param af 地址族 (AF_INET or AF_INET6)
     * @param src 点分十进制IP地址字符串
     * @param dst 指向存储二进制结果的缓冲区指针
     * @return 成功返回1，无效格式返回0，错误返回-1
     */
    static int ipStrToBIn(int af, const char* src, void* dst);

    /**
     * @brief 将网络二进制形式的IP地址转换为字符串形式。
     * @param af 地址族 (AF_INET or AF_INET6)
     * @param src 指向二进制地址的指针
     * @param dst 指向存储结果字符串的缓冲区
     * @param size 缓冲区的长度
     * @return 成功则返回指向dst的指针，失败返回NULL
     */
    static const char* binToIpStr(int af, const void* src, char* dst, socklen_t size);

    /**
     * @brief 根据主机名和服务名获取地址信息。这是进行DNS查询的首选函数。
     * @param node 主机名 (e.g., "www.google.com") 或IP地址字符串
     * @param service 服务名 (e.g., "http") 或端口号字符串 ("80")
     * @param hints 指向addrinfo结构的指针，用于过滤返回结果
     * @param res [输出] 指向addrinfo结构链表的指针
     * @return 成功返回0，失败返回非零错误码
     */
    static int getAddrInfo(const char* node, const char* service, const struct ::addrinfo* hints, struct addrinfo** res);

    /**
     * @brief 释放由getAddrInfo函数分配的addrinfo结构。
     * @param res 指向要释放的addrinfo链表的指针
     */
    static void freeAddrInfo(struct ::addrinfo* res);

    /**
     * @brief 根据sockaddr地址信息获取主机名和服务名 (反向DNS查询)。
     * @param sa 指向sockaddr结构的指针
     * @param salen sockaddr结构的长度
     * @param host [输出] 存放主机名的缓冲区
     * @param hostlen 主机名缓冲区长度
     * @param serv [输出] 存放服务名的缓冲区
     * @param servlen 服务名缓冲区长度
     * @param flags 控制标志
     * @return 成功返回0，失败返回非零错误码
     */
    static int getNameInfo(const struct sockaddr* sa, socklen_t salen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, int flags);

    /**
     * @brief 获取本地主机的标准主机名。
     * @param name [输出] 存放主机名的缓冲区
     * @param len 缓冲区长度
     * @return 成功返回0，失败返回-1
     */
    static int getHostName(char* name, size_t len);

};


// ================================================================================
// =================== 以下是所有成员函数的 inline 实现 ===========================
// ================================================================================


/*************************************** Socket 底层封装接口 ****************************************/

//================================================================================================
// 1. Socket生命周期与核心操作
//================================================================================================

// 根据指定的地址族，创建一个TCP套接字 (SOCK_STREAM)。
inline int SocketIO::createTcpSocket(int address_family)
{
    // 调用 socket() 系统调用创建一个新的套接字。
    // SOCK_STREAM: 提供有序、可靠、双向的字节流, 用于 TCP。
    // 第三个参数 protocol 通常设为0, 系统会自动选择合适的协议。
    return socket(address_family, SOCK_STREAM, 0);
}

// 根据指定的地址族，创建一个UDP套接字 (SOCK_DGRAM)。
inline int SocketIO::createUdpSocket(int address_family)
{
    // 调用 socket() 系统调用创建一个新的套接字。
    // SOCK_DGRAM: 提供无连接、不可靠的数据报服务, 用于 UDP。
    // 第三个参数 protocol 通常设为0, 系统会自动选择合适的协议。
    return socket(address_family, SOCK_DGRAM, 0);
}

// 将套接字绑定到指定的IP地址和端口。
inline int SocketIO::bindSocket(int fd, const std::string& ip, int port)
{
    if (fd < 0) {  return -1;  }

    // 判断是IPv4还是IPv6, 并填充对应的地址结构体
    if (ip.find(':') == std::string::npos) { // IPv4
        sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr)); // 使用 memset 将结构体内存清零, 这是非常重要的初始化步骤。
        server_addr.sin_family = AF_INET; // 设置地址族为 IPv4
        server_addr.sin_port = htons(port); // 使用 htons 将主机字节序的端口号转换成网络字节序。
        int ret = inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr); // 将字符串形式的IP地址转换成网络二进制格式。
        if(ret != 1){ throw std::runtime_error("error: bind -> IP address translation error"); return -1; }
        
        return bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    
    } else { // IPv6
        sockaddr_in6 server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin6_family = AF_INET6; // 设置地址族为 IPv6
        server_addr.sin6_port = htons(port);
        int ret = inet_pton(AF_INET6, ip.c_str(), &server_addr.sin6_addr);
        if(ret != 1){ throw std::runtime_error("error: bind -> IP address translation error"); return -1; }

        return bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    }
}

// 监听套接字，使其进入被动接收连接的状态。
inline int SocketIO::listenSocket(int fd)
{
    if (fd < 0) { return -1; }
    return listen(fd, SOMAXCONN); // 第二个参数 backlog 定义了等待连接队列的最大长度, SOMAXCONN 是一个系统推荐的合理值。
}

// 接受一个新的客户端连接。
inline int SocketIO::acceptSocket(int fd, struct sockaddr_storage *client_addr)
{
    if (fd < 0) { return -1; }

    if (client_addr == nullptr) {
        return accept(fd, nullptr, nullptr); 
    }
    
    socklen_t client_addr_len = sizeof(struct sockaddr_storage);
    return accept(fd, (struct sockaddr*)client_addr, &client_addr_len);
}

// 向指定IP和端口发起连接。
inline int SocketIO::connectSocket(int fd, const std::string& ip, int port)
{
    if (fd < 0) { return -1; }

    if (ip.find(':') == std::string::npos) { // IPv4
        sockaddr_in server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_port = htons(port);
        int ret = inet_pton(AF_INET, ip.c_str(), &server_addr.sin_addr);
        if(ret != 1){ throw std::runtime_error("error: connect -> IP address translation error"); return -1; }

        return connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    } else { // IPv6
        sockaddr_in6 server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sin6_family = AF_INET6;
        server_addr.sin6_port = htons(port);
        int ret = inet_pton(AF_INET6, ip.c_str(), &server_addr.sin6_addr);
        if(ret != 1){ throw std::runtime_error("error: connect -> IP address translation error"); return -1; }

        return connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    }
}

// 关闭Socket写端。
inline int SocketIO::shutdownWrite(int fd)
{
    if(fd < 0) { return -1; }   
    // 关闭 fd 的写方向。通知对端“本端不再发送数据，但可以继续接收数据”
    return shutdown(fd, SHUT_WR);
}

// 关闭Socket读端。
inline int SocketIO::shutdownRead(int fd)
{
    if(fd < 0) { return -1; }
    // 关闭连接的读方向。通知对端“本端不再接收数据，但可以继续发送数据”
    return shutdown(fd, SHUT_RD);
}

// 关闭Socket读写端。
inline int SocketIO::shutdownBoth(int fd)
{
    if(fd < 0) { return -1; }
    // 关闭连接的读和写方向。通知对端“本端不再接收和发送数据”
    return shutdown(fd, SHUT_RDWR);
}

// 关闭套接字Socket。
inline int SocketIO::closeSocket(int fd)
{
    if (fd < 0) { return -1; }
    return ::close(fd);
}

//================================================================================================
// 2. 数据传输
//================================================================================================

// 发送指定长度的全部数据 (循环发送, 确保完整性)。
inline ssize_t SocketIO::sendSocket(int fd, const char *buf, size_t len)
{
    if (fd < 0 || buf == nullptr || len == 0) { return -1; } // 无效参数

    size_t total_sent = 0;      // 已发送的总字节数
    size_t bytes_left = len;        // 剩余待发送的字节数

    // 循环发送, 直到所有字节都发送完毕
    while (total_sent < len) {
        // 调用底层的 send 函数
        // 注意:
        // 1. 发送的起始位置是 buf + total_sent
        // 2. 期望发送的长度是 bytes_left
        ssize_t bytes_sent_this_time = send(fd, buf + total_sent, bytes_left, 0);

        if (bytes_sent_this_time == -1) {
            // 如果 send 调用出错
            
            // 如果错误是 EAGAIN 或 EWOULDBLOCK, 表示发送缓冲区暂时已满。
            // 在阻塞模式下, 这不应该发生。但在非阻塞模式下, 
            // 这意味着我们应该稍后重试。对于这个阻塞函数, 我们可以简单地继续循环。
            // 实际上, 更好的做法是使用 select/poll/epoll 等待套接字变为可写。
            // 为简单起见, 我们这里只处理致命错误。
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 在这个简单的阻塞实现中, 我们可以认为这是个瞬时错误并重试
                // (或者可以加上短暂休眠, 但更好的方式是事件驱动)
                continue; 
            }
            
            // 对于其他错误 (如 EPIPE - 连接已断开), 这是一个致命错误。
            throw std::runtime_error("error: send -> failed");
            return -1; // 返回失败
        }

        if (bytes_sent_this_time == 0) {
            // send 返回 0 通常表示对端已关闭连接
            throw std::runtime_error("waring: send -> returned 0,peer has closed the connection.");
            return -1; // 同样视为失败
        }

        // 更新已发送和剩余的字节数
        total_sent += bytes_sent_this_time;
        bytes_left -= bytes_sent_this_time;
    }

    // 所有数据都成功发送, 返回发送的总字节数
    return total_sent;
}

// 接收数据 (TCP)。
inline ssize_t SocketIO::recvSocket(int fd, char *buf, size_t len)
{ 
    return recv(fd, buf, len, 0);
}

// 接收固定长度的字节。
inline ssize_t SocketIO::recvFixedLength(int fd, char *buf, size_t len)
{
    if (fd < 0 || buf == nullptr || len == 0) {
        return -1; // 无效参数
    }

    size_t total_recv = 0;
    size_t bytes_left = len;

    // 循环接收, 直到接收到所有期望的字节
    while (total_recv < len) {
        // 从 buf + total_recv 的位置开始接收剩余的 bytes_left 字节
        ssize_t bytes_recv_this_time = recv(fd, buf + total_recv, bytes_left, 0);

        if (bytes_recv_this_time == -1) {
            // 如果错误是临时的 (非阻塞模式下), 继续尝试
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                continue;
            }
            // 其他致命错误
            throw std::runtime_error("error: recvFixedLength -> failed");
            return -1;
        }

        if (bytes_recv_this_time == 0) {
            // recv 返回 0 表示对端关闭了连接
            // 如果此时还未接收完所有数据, 这是一个意外的关闭
            throw std::runtime_error("waring: recvFixedLength -> peer has closed the connection.");
            return 0; 
        }

        // 更新已接收和剩余的字节数
        total_recv += bytes_recv_this_time;
        bytes_left -= bytes_recv_this_time;
    }

    return total_recv;
}

// 接收数据直到遇到 "\r\n"。
inline bool SocketIO::recvLine(int fd, std::string& out_line)
{
    out_line.clear(); // 每次调用前先清空输出字符串
    if (fd < 0) { return false; }

    char c;
    while (true) {
        // 逐字节接收
        ssize_t result = recv(fd, &c, 1, 0);

        if (result == 1) {
            out_line += c;
            // 检查是否接收到了 "\r\n"
            if (out_line.length() >= 2 && out_line.substr(out_line.length() - 2) == "\r\n") {
                return true; // 成功找到, 返回 true
            }
        } else if (result == 0) { // 对端关闭
            return false;
        } else { // result == -1
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 在非阻塞模式下, 数据暂时不可用, 继续尝试
                continue;
            }
            // 其他致命错误
            throw std::runtime_error("error: recvLine -> failed");
            return false;
        }
    }
}

// 按 "4字节头部(网络字节序长度) + 消息体" 的格式接收数据包。
inline ssize_t SocketIO::recvPacket(int fd, std::vector<char>& out_packet, uint32_t max_packet_size)
{
    out_packet.clear(); // 每次调用前先清空
    if (fd < 0) { return -1; }

    // 1. 接收4字节的头部
    char header_buf[4];
    // 使用 MSG_WAITALL 标志保证收满4个字节, 或者直到出错/连接关闭
    ssize_t header_recv = recvFixedLength(fd, header_buf, 4); // 调用自己的辅助函数
    if (header_recv <= 0) {
        // 如果返回0, 表示对端关闭; 如果是-1, 表示出错
        return header_recv;
    }

    // 2. 解析头部, 获取消息体长度 (关键修改点)
    uint32_t body_len;
    // 直接将内存中的4个字节拷贝到 uint32_t 变量中
    memcpy(&body_len, header_buf, sizeof(uint32_t));
    // !!! 不再调用 ntohl() !!! 假设发送方使用的也是主机字节序

    // 3. 安全检查：包体长度是否超出限制
    if (body_len > max_packet_size) {
        throw std::runtime_error("error: recvPacket -> packet body size " + std::to_string(body_len) + " exceeds max limit " + std::to_string(max_packet_size));
        return -2; // 定义-2为包体超长错误
    }
    
    // 4. 准备 vector 并接收消息体
    out_packet.resize(4 + body_len);
    // 先将头部数据拷贝进去
    memcpy(out_packet.data(), header_buf, 4);

    if (body_len > 0) {
        // 接收消息体, 直接写入 vector 的内存中 (头部之后的位置)
        ssize_t body_recv = recvFixedLength(fd, out_packet.data() + 4, body_len); // 调用自己的辅助函数
        if (body_recv <= 0) {
            // 在接收消息体时连接关闭或出错
            throw std::runtime_error("waring: recvPacket -> peer has closed the connection.");
            return body_recv;
        }
    }

    // 5. 成功接收完整数据包, 返回总长度
    return out_packet.size();
}

// 从指定地址接收数据 (通常用于UDP)。
inline ssize_t SocketIO::recvfromSocket(int fd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
{
    return recvfrom(fd, buf, len, flags, src_addr, addrlen);
}

// 发送数据到指定地址 (通常用于UDP)。
inline ssize_t SocketIO::sendtoSocket(int fd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)
{
    return sendto(fd, buf, len, flags, dest_addr, addrlen);
}

//================================================================================================
// 3. Socket选项配置
//================================================================================================

// 设置指定套接字为非阻塞模式
inline void SocketIO::setNonBlocking(int fd)
{
    if (fd < 0) return;
    // 使用 fcntl (file control) 来修改文件描述符的属性。
    // 1. F_GETFL: 获取当前的文件状态标志。
    int flags = fcntl(fd, F_GETFL, 0);
    // 2. 使用位或操作 `|` 添加 O_NONBLOCK (非阻塞) 标志。
    // 3. F_SETFL: 将修改后的标志设置回去。
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

// 设置指定套接字为阻塞模式
inline void SocketIO::setBlocking(int fd)
{
    if (fd < 0) return;
    int flags = fcntl(fd, F_GETFL, 0);
    // 使用位与和取反操作 `& ~` 来移除 O_NONBLOCK 标志。
    fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
}

// 设置地址可重用
inline int SocketIO::setReuseAddr(int fd, bool on)
{
    if (fd < 0) return -1;
    int optval = on ? 1 : 0;
    // SO_REUSEADDR: 允许立即重用处于 TIME_WAIT 状态的地址和端口。
    // 这对于需要频繁重启的服务器程序非常重要。
    return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
}

// 设置端口可重用
inline int SocketIO::setReusePort(int fd, bool on)
{
    if (fd < 0) return -1;
    int optval = on ? 1 : 0;
    // SO_REUSEPORT: 允许多个进程或线程绑定到完全相同的IP地址和端口。
    // 可用于实现内核级别的负载均衡。
    return setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
}

// 禁用Nagle算法
inline int SocketIO::setTcpNoDelay(int fd, bool on)
{
    if (fd < 0) return -1;
    int optval = on ? 1 : 0;
    // TCP_NODELAY: 禁用 Nagle 算法。
    // Nagle算法会尝试合并小的TCP包以提高网络效率, 但会引入延迟。
    // 对于实时性要求高的应用(如游戏、远程控制), 通常需要禁用它。
    return setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
}

// 启用TCP保活机制
inline int SocketIO::setKeepAlive(int fd, bool on)
{
    if (fd < 0) return -1;
    int optval = on ? 1 : 0;
    // SO_KEEPALIVE: 开启TCP的保活机制。
    // 系统会周期性地发送探测包来检查连接是否仍然有效, 可用于检测"僵尸连接"。
    return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
}

// 设置接收缓冲区大小 (SO_RCVBUF)。
inline int SocketIO::setRecvBufferSize(int fd, int size)
{
    if (fd < 0) return -1;
    return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
}

// 设置发送缓冲区大小 (SO_SNDBUF)。
inline int SocketIO::setSendBufferSize(int fd, int size)
{
    if (fd < 0) return -1;
    return setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
}

// 设置接收超时 (SO_RCVTIMEO)。
inline int SocketIO::setRecvTimeout(int fd, int seconds)
{
    if (fd < 0) return -1;
    struct timeval timeout = { seconds, 0 };
    return setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
}


// 设置发送超时时间
inline int SocketIO::setSendTimeout(int fd, int seconds)
{
    if (fd < 0) return -1;
    // SO_RCVTIMEO: 设置接收操作的超时时间。
    // 在Linux上, 需要使用 timeval 结构体来设置。
    struct timeval timeout = { seconds, 0 }; // 秒, 微秒
    return setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
}

//================================================================================================
// 4. 静态网络工具函数
//================================================================================================

// IP地址转换到数字
inline int SocketIO::ipStrToBIn(int af, const char* src, void* dst)
{
    return inet_pton(af, src, dst);
}

// 数字转换成IP地址
inline const char* SocketIO::binToIpStr(int af, const void* src, char* dst, socklen_t size)
{
    return inet_ntop(af, src, dst, size);
}

// 获取地址信息
inline int SocketIO::getAddrInfo(const char* node, const char* service, const struct ::addrinfo* hints, struct ::addrinfo** res)
{
    return ::getaddrinfo(node, service, hints, res);
}

// 释放地址信息
inline void SocketIO::freeAddrInfo(struct ::addrinfo* res)
{
    ::freeaddrinfo(res); // 释放由 getaddrinfo 分配的内存。
}

// 获取名称信息
inline int SocketIO::getNameInfo(const struct sockaddr* sa, socklen_t salen, char* host, socklen_t hostlen, char* serv, socklen_t servlen, int flags)
{
    return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
}

// 获取本地主机的标准主机名。
inline int SocketIO::getHostName(char* name, size_t len)
{
    return gethostname(name, len);
}

} // 结束 namespace xdg

#endif // _XDGSOCKETIO_HPP_